package com.tianji.learning.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constants.RedisConstants;
import com.tianji.learning.domain.po.PointsRecord;
import com.tianji.learning.domain.vo.PointsStatisticsVO;
import com.tianji.learning.enums.PointsRecordType;
import com.tianji.learning.mapper.PointsRecordMapper;
import com.tianji.learning.service.IPointsRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 学习积分记录，每个月底清零 服务实现类
 * </p>
 *
 * @author taohongrun
 * @since 2025-02-11
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class PointsRecordServiceImpl extends ServiceImpl<PointsRecordMapper, PointsRecord> implements IPointsRecordService {
    private final StringRedisTemplate redisTemplate;
    @Override
    public void addPointsRecord(Long userId, int i, PointsRecordType pointsRecordType) {
        int maxPoints = pointsRecordType.getMaxPoints();
        LocalDateTime now = LocalDateTime.now();
        //查询本日该类型积分  字段为函数查询需要在mapper编写
        Integer todayPoints = getTotalPoints(userId, now, pointsRecordType);
        if (maxPoints > 0  && todayPoints >= maxPoints) throw new RuntimeException("今日该类型积分已达上限");
        //其余情况均为直接添加记录即可
        //保证积分不超过当日上限
        int realyPoints = i;
        if (maxPoints != 0) realyPoints=Math.min((maxPoints - todayPoints), i);
        log.info("实际应加分数:{}",realyPoints);
        PointsRecord pointsRecord = new PointsRecord();
        pointsRecord.setUserId(userId);

        pointsRecord.setPoints(realyPoints);
        pointsRecord.setType(pointsRecordType);
        pointsRecord.setCreateTime(now);
        save(pointsRecord);

        //更新redis的积分排行榜数据
        String key = StrUtil.format(RedisConstants.POINTS_BOARD_KEY, DateUtil.format(now, "yyyyMM"));
        redisTemplate.opsForZSet().incrementScore(key, userId.toString(), realyPoints);

    }

    @Override
    public List<PointsStatisticsVO> queryMyPointsToday() {
        // 1.获取用户
        Long userId = UserContext.getUser();
        // 2.获取日期
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime begin = DateUtils.getDayStartTime(now);
        LocalDateTime end = DateUtils.getDayEndTime(now);
        // 3.构建查询条件
        QueryWrapper<PointsRecord> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(PointsRecord::getUserId, userId)
                .between(PointsRecord::getCreateTime, begin, end)
                .groupBy(PointsRecord::getType);
        // 4.查询
        List<PointsRecord> list = getBaseMapper().queryUserPointsByDate(wrapper);
        if (list.isEmpty()) {
            return CollUtil.empty(PointsRecord.class);
        }
        // 5.封装返回
        List<PointsStatisticsVO> vos = new ArrayList<>();
        for (PointsRecord p : list) {
            PointsStatisticsVO vo = new PointsStatisticsVO();
            vo.setType(p.getType().getDesc());
            vo.setMaxPoints(p.getType().getMaxPoints());
            vo.setPoints(p.getPoints());
            vos.add(vo);
        }
        return vos;
    }

    public Integer getTotalPoints(Long userId, LocalDateTime now, PointsRecordType pointsRecordType) {
        QueryWrapper<PointsRecord> pointsRecordQueryWrapper = new QueryWrapper<>();
        pointsRecordQueryWrapper
                .lambda()
                .eq(PointsRecord::getUserId, userId)
                .eq(PointsRecord::getType, pointsRecordType)
                .between(PointsRecord::getCreateTime, now.toLocalDate().atStartOfDay(), now.toLocalDate().atTime(23, 59, 59));
        Integer i = getBaseMapper().selectSumPoints(pointsRecordQueryWrapper);
        log.info("查询用户:{}积分记录,积分类型:{},总积分:{}", userId, pointsRecordType, i);
        return i;
    }


}
